package orm

import (
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"gorm.io/gorm/schema"
	"log"
	"reflect"
)

type sqliteAdapt struct {
	DB *gorm.DB
}

func NewSqliteAdapt(cfg *DbConfig) IOrm {
	db, err := gorm.Open(sqlite.Open(cfg.SqliteFile), &gorm.Config{})
	if err != nil {
		log.Fatalln("err:", err.Error())
	}
	adapt := sqliteAdapt{
		DB: db,
	}
	return adapt
}

func (s sqliteAdapt) Insert(value interface{}) error {
	return s.DB.Debug().Create(value).Error
}

func (s sqliteAdapt) AutoMigrate(dst ...interface{}) error {
	if len(dst) == 0 {
		log.Println("dst is empty!")
	}
	return s.DB.AutoMigrate(dst...)
}

func (s sqliteAdapt) SelectById(id uint, data interface{}) error {
	result := s.DB.Debug().Where(" id = ? ", id).Find(data)
	if result.RowsAffected <= 0 {
		return gorm.ErrRecordNotFound
	}
	return result.Error
}

func (s sqliteAdapt) Select(table schema.Tabler, data interface{}) error {
	return s.DB.Debug().Table(table.TableName()).Where(table).Find(data).Error
}

func (s sqliteAdapt) SelectList(query *Query, data interface{}) error {
	return s.DB.Debug().Table(query.TableName).Where(query.QueryBuilder.String(), query.QueryArgs...).Find(data).Error
}

func (s sqliteAdapt) SelectCount(query *Query) (count int64, err error) {
	err = s.DB.Debug().Table(query.TableName).Where(query.QueryBuilder.String(), query.QueryArgs...).Count(&count).Error
	return
}

func (s sqliteAdapt) SelectPage(query *Query, data interface{}) (count int64, err error) {
	count, err = s.SelectCount(query)
	if err != nil {
		return 0, err
	}

	err = s.DB.Debug().Scopes(paginate(query.Page, query.Size)).Where(query.QueryBuilder.String(), query.QueryArgs...).Find(data).Error

	//.Scan() 不会自动推导类型
	//typ := getReturnType(table)
	//data := reflect.New(reflect.SliceOf(typ)).Elem().Interface()
	//err = s.DB.Debug().Scopes(paginate(query.Page, query.Size)).Where(query.QueryBuilder.String(), query.QueryArgs...).Scan(data).Error
	if err != nil {
		return 0, err
	}
	return
}

func getReturnType(table schema.Tabler) reflect.Type {
	typ := reflect.TypeOf(table)
	if typ.Kind() == reflect.Ptr {
		return typ.Elem()
	}
	return typ
}

func paginate(page, size int) func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		if page <= 0 {
			page = 1
		}
		if size <= 0 {
			size = 10
		}
		return db.Offset((page - 1) * size).Limit(size)
	}
}

func (s sqliteAdapt) DeleteById(table schema.Tabler, id uint) error {
	return s.DB.Debug().Delete(table, id).Error
}

func (s sqliteAdapt) UpdateColumnById(table schema.Tabler, column string, value interface{}) error {
	var id interface{}
	v := reflect.ValueOf(table)
	switch v.Kind() {
	case reflect.Ptr:
		id = reflect.ValueOf(table).Elem().FieldByName("ID").Interface()
	case reflect.Struct:
		id = reflect.ValueOf(table).FieldByName("ID").Interface()
	default:
		id = reflect.ValueOf(table).FieldByName("ID").Interface()
	}
	return s.DB.Debug().Table(table.TableName()).Where(" id = ? ", id).UpdateColumn(column, value).Error
}
